package com.itheima.user.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.itheima.user.entity.OrderEntity;
import com.itheima.user.entity.UserEntity;
import com.itheima.user.feign.OrderService;
import com.itheima.user.service.UserService;
import com.itheima.user.vo.request.AddOrderVO;
import com.itheima.user.vo.response.OrderResultVO;
import com.itheima.user.vo.response.ResultVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/user")

//@CrossOrigin //允许跨域访问,可以定义在类上或方法上 (配置config全局跨域,就不用了)

@RefreshScope //开启分布式配置中心动态刷新
public class UserController {

    @Autowired
    private UserService userService;

    //用户登录
    @GetMapping("/login/{userName}/{password}")
    public ResultVO login(@PathVariable("userName") String userName, @PathVariable("password") String password) {
        boolean loginResult = userService.login(userName, password);
        ResultVO result = new ResultVO();
        if (loginResult) {
            result.setSuccess(true);
        } else {
            result.setSuccess(false);
        }
        return result;
    }

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private OrderService orderService;

    //查询用户订单信息
    @GetMapping("/findUserOrders/{userId}")
    public OrderResultVO findUserOrders(@PathVariable("userId") Integer userId) {

        int i = 1/0;

        OrderResultVO orderResultVO = new OrderResultVO();
        UserEntity userEntity = userService.findUserById(userId);

        //todo
        /*//(分布式架构模式下) 直接调用订单服务,根据id获取订单列表
        String url = "http://localhost:9001/order/findOrderInfoByUserId/" + userId;
        //restTemplate 发起远程网络请求
        //根据url 请求访问订单服务接口的数据
        List<OrderEntity> orderList = restTemplate.getForObject(url, List.class);*/

        //todo 利用eureka注册中心动态获取
        //动态从注册中心获取服务路径(nacos同样适用)
        //getInstancesById,返回值是集合: 因为ORDER_SERVICE可能是集群.
    /*  List<ServiceInstance> instanceList = discoveryClient.getInstances("order-service");
        if (instanceList == null || instanceList.size() == 0) {
            return null;
        }
        ServiceInstance serviceInstance = instanceList.get(0);
        String host = serviceInstance.getHost();
        System.out.println(serviceInstance.getHost());
        int port = serviceInstance.getPort();
        System.out.println(serviceInstance.getPort());

        //String url = "http://localhost:9001/order/findOrderInfoByUserId/"+userId;
        String url = "http://" + host + ":" + port + "/order/findOrderInfoByUserId/" + userId;

        //还可以直接基于服务名称完成调用
        //String url = "http://order-service/order/findOrderInfoByUserId/"+userId;

        List<OrderEntity> orderList = restTemplate.getForObject(url, List.class);
        */

        //todo 基于feign完成远程调用(就像调用本地方法,其实是通过feign的解析 找到对应方法,发起远程调用)
        List<OrderEntity> orderList = orderService.findOrderInfoByUserId(userId);

        orderResultVO.setUserName(userEntity.getUserName());
        orderResultVO.setOrderList(orderList);

        return orderResultVO;
    }

    //添加订单
    @PostMapping("/addUserOrder")
    public ResultVO addUserOrder(@RequestBody AddOrderVO addOrderVO) {
        ResultVO result = new ResultVO();
        //判断用户是否存在
        UserEntity userEntity = userService.findUserById(addOrderVO.getUserId());
        if (userEntity == null) {
            result.setSuccess(false);
            return result;
        }

        //todo

        return result;
    }

    /*@RequestMapping("/hello")
    public String hello(String company) {
        return "hello user service,company : " + company;
    }*/

    @Value("${company}")
    private String company;

    @Value("${commonKey}")
    private String commonKey;

    //不同的开发环境下都会去加载user-service.yml，也就是没有指定特定环境的文件。那么对于通用配置就可以设置在这个文件中
    //company 会读取user-service-test.yml的值 ,commonKey会读取user-service.yml的值
    @RequestMapping("/hello")
    public String hello() {
        return "hello user service,company : " + company + "    commonKey : " + commonKey;
    }

    //todo sentinel 关联 限流测试(hello2限流,hello1不能访问)
    //资源1
    @GetMapping(value = "/hello1")
    public String hello1() {
        return "Hello Sentinel1";
    }

    //资源2
    @GetMapping(value = "/hello2")
    public String hello2() {
        return "Hello Sentinel2";
    }

    //todo sentinel 链路 限流测试
    //资源3
    //每秒访问2次,限流后 userService.dosomething(); 不能继续访问
    @GetMapping(value = "/hello3")
    public String hello3() {
        userService.dosomething();
        return "Hello Sentinel3";
    }

    //资源4
    //没有设置限流,userService.dosomething(); 因为入口不同,可以继续访问
    @GetMapping(value = "/hello4")
    public String hello4() {
        userService.dosomething();
        return "Hello Sentinel4";
    }

    //todo 熔断降级
    //资源5 响应时间测试
    @GetMapping(value = "/hello5/{flag}")
    public String hello5(@PathVariable("flag") int flag) throws InterruptedException {
        if (flag == 1){
            TimeUnit.SECONDS.sleep(3);
        }
        return "Hello Sentinel5";
    }

    //资源6 异常比例,异常数测试
    @GetMapping(value = "/hello6/{flag}")
    public String hello6(@PathVariable("flag") int flag) throws InterruptedException {
        if (flag == 1){
            int i =1/0;
        }
        return "Hello Sentinel6";
    }

    //todo 热点参数限流
    //资源7 参数(热点)规则限流
    @GetMapping(value = "/hello7")
    @SentinelResource(value = "hello7",blockHandler = "helloHotHandler") //声明资源名称
    public String hello7(@RequestParam(value = "userId",required = false) Integer userId) {
        //@RequestParam(value = "userId",required = false) 默认true,必须携带id参数

        return "Hello Sentinel7";
    }

    //该方法返回值类型、形参数量、形参类型、形参名称需要与原方法一致
    public String helloHotHandler(Integer userId,BlockException e){

        return "访问被限流了,请稍后重试!";
    }

    /**
     * @SentinelResource(value = "hello7",blockHandler = "helloHotHandler")  处理BlockException 流控异常
     * @SentinelResource(value = "hello7",fallbackClass = GlobalFallBackHandler.class,fallback = "helloHotHandler")  处理运行时异常
     *
     * blockHandlerClass = GlobalFallBackHandler.class,用于指定全局处理异常的类
     * fallbackClass = GlobalFallBackHandler.class,用于指定全局处理异常的类
     */
}
